package cn.caidabao.gb.component.sip.server.request.recieve;

import cn.caidabao.gb.bean.*;
import cn.caidabao.gb.component.sip.server.storage.CallBackStorage;
import cn.caidabao.gb.component.sip.server.storage.SessionStorage;
import cn.caidabao.gb.util.CallBackIdUtils;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sip.RequestEvent;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ContentTypeHeader;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

@Component
@Slf4j
public class DefaultMessageRequestHandler implements RequestHandler<Void> {
    @Resource
    private SessionStorage sessionStorage;
    @Resource
    private CallBackStorage callBackStorage;
    private ConcurrentMap<String,List<RecordTimeInfo>> recordInfoCache  = new ConcurrentHashMap<>();
    @SneakyThrows
    @Override
    public Void handleRequest(RequestEvent event, GBSipContext sipContext){
        SIPRequest request = (SIPRequest) event.getRequest();
        ContentTypeHeader contentTypeHeader = (ContentTypeHeader)request.getHeader(ContentTypeHeader.NAME);
        CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
        if ("Application".equals(contentTypeHeader.getContentType())&&"MANSCDP+xml".equals(contentTypeHeader.getContentSubType())){
            String content = new String((byte[]) request.getContent());
            Document document = DocumentHelper.parseText(content);
            Element rootElement = document.getRootElement();
            String name = rootElement.getQName().getName();
            if ("Notify".equals(name)){
                Node cmdType = rootElement.selectNodes("CmdType").get(0);
                if ("Keepalive".equals(cmdType.getText())){
                    String deviceID = rootElement.selectNodes("DeviceID").get(0).getText();
                    String status = rootElement.selectNodes("Status").get(0).getText();
                    if ("OK".equals(status)){
                        GBSipRegisterSession gbSipRegisterSession = SessionStorage.gbSessionStorage.get(deviceID);
                        if (gbSipRegisterSession ==null){
                            log.info("收到设备{}心跳,没有找到设备，不做任何操作",deviceID);
                        }else {
                            SIPResponse response = request.createResponse(200);
                            sipContext.getSipProvider().sendResponse(response);
                            log.info("收到设备{}心跳回复200",deviceID);
                        }

                    }
                }
            }else if ("Response".equals(name)){
                Node cmdTypeNode = rootElement.selectSingleNode("CmdType");
                String cmdType = cmdTypeNode.getText();
                if (cmdType.equals("Catalog")){
                    String deviceId = rootElement.selectSingleNode("DeviceID").getText();
                    log.info("收到设备{}的catalog请求,请求callId{}",deviceId,callIdHeader.getCallId());
                    String sumNum = rootElement.selectSingleNode("SumNum").getText();
                    Node deviceListNode = rootElement.selectSingleNode("DeviceList");
                    GBSipRegisterSession session = sessionStorage.getSession(deviceId);
                    ConcurrentMap<String, GBChannel> channelMap = session.getChannelMap();
                    List<Node> items = deviceListNode.selectNodes("Item");
                    for (Node item : items) {
                        String channelId = item.selectSingleNode("DeviceID").getText();
                        String channelName = item.selectSingleNode("Name").getText();
                        String status = item.selectSingleNode("Status").getText();
                        GBChannel channel = channelMap.computeIfAbsent(channelId, ci -> new GBChannel().setChannelId(ci));
                        channel.setChannelName(channelName);
                        channel.setStatus(status);
                    }
                    String sn = rootElement.selectSingleNode("SN").getText();
                    String callBackId = CallBackIdUtils.generateDeviceInfoMessageCallBackId(deviceId, sn);
                    OGSipCallIdCallBack callBack = callBackStorage.getAndDeleteCallBack(callBackId);
                    callBack.setResult("success");
                }else if(cmdType.equals("RecordInfo")){
                    String deviceID = rootElement.selectSingleNode("DeviceID").getText();
                    String sn = rootElement.selectSingleNode("SN").getText();
                    String key = CallBackIdUtils.generateRecordInfoMessageCallBackId(deviceID, sn);
                    log.info("收到设备{}的catalog请求,请求callId{}",deviceID,callIdHeader.getCallId());
                    List<RecordTimeInfo> recordTimeInfos = recordInfoCache.computeIfAbsent(key,k->new CopyOnWriteArrayList<RecordTimeInfo>());
                    Integer sumNum = Integer.valueOf(rootElement.selectSingleNode("SumNum").getText());
                    List<Node> items = rootElement.selectSingleNode("RecordList").selectNodes("Item");
                    List<RecordTimeInfo> collect = items.stream().map(item -> {
                        RecordTimeInfo info = new RecordTimeInfo();
                        info.setStartTime(item.selectSingleNode("StartTime").getText());
                        info.setEndTime(item.selectSingleNode("EndTime").getText());
                        return info;
                    }).collect(Collectors.toList());
                    recordTimeInfos.addAll(collect);
                    log.info("收到{}的{}条历史记录",deviceID,collect.size());
                    if (recordTimeInfos.size()>=sumNum){
                        recordInfoCache.remove(key);
                        OGSipCallIdCallBack callBack = callBackStorage.getAndDeleteCallBack(key);
                        recordTimeInfos.sort(Comparator.comparing(RecordTimeInfo::getStartTime));
                        callBack.setResult(recordTimeInfos);
                    }
                }else {
                    log.warn("收到不支持的message类型，内容:{}",content);
                }
                event.getServerTransaction().sendResponse(request.createResponse(200));
            }else {
                log.warn("收到不支持的message类型，内容:{}",content);

            }
        }

        return null;
    }
}
